home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / IFC_112 / netscape / application / TextParagraph.java < prev    next >
Encoding:
Text File  |  1999-05-28  |  66.3 KB  |  1,961 lines  |  [TEXT/CWIE]

  1. // TextParagraph.java
  2. // By Ned Etcode
  3. // Copyright 1995, 1996, 1997 Netscape Communications Corp.  All rights reserved.
  4.  
  5. package netscape.application;
  6.  
  7. import netscape.util.*;
  8.  
  9.  
  10. /** Object representing a paragraph (a sequence of TextStyleRuns) formatted
  11.   * according to a TextParagraphFormat and ending with a return
  12.   * character.<br><br>
  13.   * <i><b>Note:</b> This class mostly works, but its API has not been refined
  14.   * or reviewed, and remains mostly undocumented for now.</i>
  15.   * @private
  16.   * @note 1.0 changes
  17.   */
  18. public class TextParagraph implements Cloneable, Codable {
  19.     TextView            _owner;
  20.     TextParagraphFormat _format;
  21.     Vector              _runVector;
  22.     int                 _y, _height, _lineBreaks[], _breakCount,
  23.                         _lineHeights[], _heightCount, _baselines[],
  24.                         _baselineCount, _lineRemainders[], _remainderCount,
  25.                         _charCount, _startChar;
  26.  
  27.     static final String         FORMAT_KEY = "format";
  28.     static final String         RUNVECTOR_KEY = "runVector";
  29.  
  30.  
  31.  
  32. /* constructors */
  33.  
  34.      public TextParagraph() {
  35.         super();
  36.     }
  37.  
  38.      TextParagraph(TextView owner) {
  39.         this();
  40.         init(owner);
  41.     }
  42.  
  43.      TextParagraph(TextView owner, TextParagraphFormat format) {
  44.         this();
  45.  
  46.         init(owner, format);
  47.     }
  48.  
  49.  
  50.  
  51. /* initializers */
  52.  
  53.  
  54.      void init(TextView owner, TextParagraphFormat format) {
  55.         _owner = owner;
  56.  
  57.         _runVector = new Vector();
  58.  
  59.         setFormat(format);
  60.     }
  61.  
  62.      void init(TextView owner) {
  63.         init(owner, null);
  64.     }
  65.  
  66.     Object objectAt(Vector vector, int index) {
  67.         return (index < 0 || index >= vector.count()) ? null :
  68.                                                        vector.elementAt(index);
  69.     }
  70.  
  71.     public Object clone() {
  72.         TextParagraph   cloneParagraph;
  73.         TextStyleRun    nextRun;
  74.         Object          clone = null;
  75.         int             i, count;
  76.  
  77.         collectEmptyRuns();
  78.  
  79.         try {
  80.             clone = super.clone();
  81.         } catch (CloneNotSupportedException e) {
  82.             throw new InconsistencyException(this + ": clone() not supported :" + e);
  83.         }
  84.  
  85.         if (clone != null) {
  86.             cloneParagraph = (TextParagraph)clone;
  87.             cloneParagraph._owner = null;
  88.             if( _format != null )
  89.                 cloneParagraph._format = (TextParagraphFormat)_format.clone();
  90.             else
  91.                 cloneParagraph._format = null;
  92.             cloneParagraph._runVector = new Vector();
  93.             count = _runVector.count();
  94.             for (i = 0; i < count; i++) {
  95.                 nextRun = (TextStyleRun)_runVector.elementAt(i);
  96.                 cloneParagraph.addRun(nextRun.createEmptyRun());
  97.             }
  98.             cloneParagraph._lineBreaks = null;
  99.             cloneParagraph._lineHeights = null;
  100.             cloneParagraph._baselines = null;
  101.             cloneParagraph._lineRemainders = null;
  102.         }
  103.  
  104.         return clone;
  105.     }
  106.  
  107.      void setOwner(TextView owner) {
  108.         _owner = owner;
  109.     }
  110.  
  111.      TextView owner() {
  112.         return _owner;
  113.     }
  114.  
  115.     void setY(int y) {
  116.         _y = y;
  117.     }
  118.  
  119.     void setStartChar(int absPosition) {
  120.         _startChar = absPosition;
  121.     }
  122.  
  123.     void setFormat(TextParagraphFormat format) {
  124.         if( format == null && _format == null )
  125.             return;
  126.         if (format != null)
  127.             _format = (TextParagraphFormat)format.clone();
  128.         else
  129.             _format = null;
  130.         if( _charCount > 0 )
  131.             computeLineBreaksAndHeights(_owner.bounds.width);
  132.     }
  133.  
  134.    TextParagraphFormat format() {
  135.      return _format;
  136.    }
  137.  
  138.    TextParagraphFormat currentParagraphFormat() {
  139.        if( _format != null )
  140.            return _format;
  141.        else {
  142.            TextParagraphFormat f = null;
  143.            if(_owner != null)
  144.                f = (TextParagraphFormat)_owner.defaultAttributes().get(
  145.                                                                                 TextView.PARAGRAPH_FORMAT_KEY);
  146.            if( f != null )
  147.                return f;
  148.            else {
  149.                return new TextParagraphFormat();
  150.            }
  151.        }
  152.    }
  153.  
  154.   /**
  155.    * Returns the TextParagraph's Vector of TextStyleRuns.
  156.    */
  157.      Vector runVector() {
  158.         return _runVector;
  159.     }
  160.  
  161.      TextStyleRun firstRun() {
  162.          return (TextStyleRun) _runVector.firstElement();
  163.      }
  164.  
  165.      TextStyleRun lastRun() {
  166.          return (TextStyleRun) _runVector.lastElement();
  167.      }
  168.  
  169.   /**
  170.    * Makes the TextStyleRun <b>aRun</b> as the last TextStyleRun in the
  171.    * TextParagraph.
  172.    */
  173.      void addRun(TextStyleRun aRun) {
  174.         if (aRun != null) {
  175.             aRun.setParagraph(this);
  176.             _runVector.addElement(aRun);
  177.         }
  178.     }
  179.  
  180.     /* Remove all empty runs but the first one */
  181.     void collectEmptyRuns() {
  182.         int i,c;
  183.         TextStyleRun run;
  184.         Hashtable attr;
  185.  
  186.         for(i=1,c=_runVector.count() ; i < c ; i++ ) {
  187.             run = (TextStyleRun) _runVector.elementAt(i);
  188.             if( run.charCount() == 0) {
  189.                 if(!( run._attributes != null &&
  190.                       run._attributes.get(TextView.LINK_DESTINATION_KEY) != null)) {
  191.                     _runVector.removeElementAt(i);
  192.                     i--;
  193.                     c--;
  194.                 }
  195.             }
  196.         }
  197.     }
  198.  
  199.   /**
  200.    * Adds the TextStyleRuns contained in <b>runVector</b> to the TextParagraph
  201.    * by
  202.    * calling <b>addRun()</b> for each.
  203.    */
  204.      void addRuns(Vector runVector) {
  205.         int     count, i;
  206.  
  207.         if (runVector != null) {
  208.             count = runVector.count();
  209.             for (i = 0; i < count; i++) {
  210.                 addRun((TextStyleRun)runVector.elementAt(i));
  211.             }
  212.         }
  213.     }
  214.  
  215.   /**
  216.    * Adds the TextStyleRun <b>aRun</b> to the TextParagraph, inserting it at
  217.    * <b>index</b> within the TextParagraph's runVector.
  218.    */
  219.      void insertRunAt(TextStyleRun aRun, int index) {
  220.         TextStyleRun    fontRun;
  221.  
  222.         if (aRun != null && index >= 0) {
  223.             aRun.setParagraph(this);
  224.             _runVector.insertElementAt(aRun, index);
  225.         } else {
  226. //            System.out.println("Cannot insert run " + aRun.toString() + " at index " + index);
  227.         }
  228.     }
  229.  
  230.   /**
  231.    * Returns the TextStyleRun preceeding <b>aRun</b> in the TextParagraph's
  232.    * runVector.
  233.    */
  234.      TextStyleRun runBefore(TextStyleRun aRun) {
  235.         int     index;
  236.  
  237.         if (aRun == null) {
  238.             return null;
  239.         }
  240.  
  241.         index = _runVector.indexOfIdentical(aRun);
  242.         if (index < 1) {
  243.             return null;
  244.         }
  245.  
  246.         return (TextStyleRun)_runVector.elementAt(index - 1);
  247.     }
  248.  
  249.   /**
  250.    * Returns the TextStyleRun after <b>aRun</b> in the TextParagraph's
  251.    * runVector.
  252.    */
  253.      TextStyleRun runAfter(TextStyleRun aRun) {
  254.         int     index;
  255.  
  256.         if (aRun == null) {
  257.             return null;
  258.         }
  259.  
  260.         index = _runVector.indexOfIdentical(aRun);
  261.         if (index == (_runVector.count() - 1)) {
  262.             return null;
  263.         }
  264.  
  265.         return (TextStyleRun)_runVector.elementAt(index + 1);
  266.     }
  267.  
  268.  
  269.   /**
  270.    * Returns a Vector containing all TextStyleRuns preceeding <b>aRun</b>
  271.    * in the TextParagraph's runVector.
  272.    */
  273.      Vector runsBefore(TextStyleRun aRun) {
  274.         Vector       runVector;
  275.         int             i, index;
  276.  
  277.         runVector = TextView.newVector();
  278.  
  279.         if (aRun == null) {
  280.             return runVector;
  281.         }
  282.  
  283.         index = _runVector.indexOfIdentical(aRun);
  284.         if (index == -1) {
  285.             return runVector;
  286.         }
  287.  
  288.         for (i = 0; i < index; i++) {
  289.             runVector.addElement(_runVector.elementAt(i));
  290.         }
  291.  
  292.         return runVector;
  293.     }
  294.  
  295.   /**
  296.    * Returns a Vector containing all TextStyleRuns following <b>aRun</b> in
  297.    * the
  298.    * TextParagraph's runVector.
  299.    */
  300.      Vector runsAfter(TextStyleRun aRun) {
  301.         Vector       runVector;
  302.         int             i, count;
  303.  
  304.         runVector = TextView.newVector();
  305.  
  306.         if (aRun == null) {
  307.             return runVector;
  308.         }
  309.  
  310.         i = _runVector.indexOfIdentical(aRun);
  311.         if (i == -1) {
  312.             return runVector;
  313.         }
  314.  
  315.         count = _runVector.count();
  316.         for (; i < count; i++) {
  317.             runVector.addElement(_runVector.elementAt(i));
  318.         }
  319.  
  320.         return runVector;
  321.     }
  322.  
  323.   /**
  324.    * Returns a Vector containing all TextStyleRuns between (and including)
  325.    * <b>startRun</b> and <b>endRun</b> in the TextParagraph's runVector.
  326.    * If <b>startRun</b> is <b>null</b>, this method starts at the first
  327.    * run in the runVector.  If <b>endRun</b> is <b>null</b>, this method
  328.    * ends with the last run in the runVector.
  329.    */
  330.      Vector runsFromTo(TextStyleRun startRun, TextStyleRun endRun) {
  331.         Vector       runVector;
  332.         int             i, end;
  333.  
  334.         runVector = TextView.newVector();
  335.  
  336.         if (startRun == endRun && startRun != null) {
  337.             runVector.addElement(startRun);
  338.  
  339.             return runVector;
  340.         }
  341.  
  342.         if (startRun == null) {
  343.             i = 0;
  344.         } else {
  345.             i = _runVector.indexOfIdentical(startRun);
  346.         }
  347.  
  348.         if (endRun == null) {
  349.             end = _runVector.count() - 1;
  350.         } else {
  351.             end = _runVector.indexOfIdentical(endRun);
  352.         }
  353.  
  354.         if (i < 0 || end < 0) {
  355.             return runVector;
  356.         }
  357.  
  358.         for (; i <= end; i++) {
  359.             runVector.addElement(_runVector.elementAt(i));
  360.         }
  361.  
  362.         return runVector;
  363.     }
  364.  
  365.   /**
  366.    * Removes the TextStyleRun <b>aRun</b> from the TextParagraph.
  367.    */
  368.      void removeRun(TextStyleRun aRun) {
  369.         if (aRun != null) {
  370.             _runVector.removeElement(aRun);
  371.         }
  372.     }
  373.  
  374.   /**
  375.    * Removes the TextStyleRuns contained in <b>runVector</b> from the
  376.    * TextParagraph.
  377.    */
  378.      void removeRuns(Vector runVector) {
  379.         int     i;
  380.  
  381.         if (runVector == null) {
  382.             return;
  383.         }
  384.  
  385.         i = runVector.count();
  386.         while (i-- > 0) {
  387.             _runVector.removeElement(runVector.elementAt(i));
  388.         }
  389.     }
  390.  
  391.   /**
  392.    * Removes the TextStyleRun located at <b>index</b> within the TextParagraph's
  393.    * runVector from the TextParagraph.
  394.    */
  395.      void removeRunAt(int index) {
  396.         _runVector.removeElementAt(index);
  397.     }
  398.  
  399.   /**
  400.    * Returns <b>true</b> if the TextParagraph contains no TextStyleRuns.
  401.    */
  402.      boolean isEmpty() {
  403.         TextStyleRun    nextRun;
  404.         int             i, count = 0;
  405.  
  406.         i = _runVector.count();
  407.         while (i-- > 0 && count == 0) {
  408.             nextRun = (TextStyleRun)_runVector.elementAt(i);
  409.             count += nextRun.charCount();
  410.         }
  411.  
  412.         return (count == 0);
  413.     }
  414.  
  415.  
  416.     int[] _growArrayTo(int anArray[], int newSize) {
  417.         int     i, oldArray[];
  418.  
  419.         if (newSize < 1) {
  420.             return anArray;
  421.         }
  422.  
  423.         if (anArray != null && anArray.length >= newSize) {
  424.             return anArray;
  425.         }
  426.  
  427.         oldArray = anArray;
  428.         if (anArray != null) {
  429.             i = anArray.length;
  430.             while (i < newSize) {
  431.                 i *= 2;
  432.             }
  433.         } else {
  434.             i = 20;
  435.         }
  436.  
  437.         anArray = new int[i];
  438.  
  439.         if (oldArray == null) {
  440.             return anArray;
  441.         }
  442.  
  443.         System.arraycopy(oldArray, 0, anArray, 0, oldArray.length);
  444.  
  445.         return anArray;
  446.     }
  447.  
  448.     void _addLineBreak(int position) {
  449.         int     i, count;
  450.  
  451.         if (position < 0) {
  452.             return;
  453.         }
  454.  
  455.         _lineBreaks = _growArrayTo(_lineBreaks, _breakCount + 1);
  456.         _lineBreaks[_breakCount] = position;
  457.         _breakCount++;
  458.     }
  459.  
  460.     void _addLineHeightAndBaseline(int height, int baseline) {
  461.         int     i, count;
  462.  
  463.         if (height < 0 || baseline < 0) {
  464.             return;
  465.         }
  466.  
  467.         _lineHeights = _growArrayTo(_lineHeights, _heightCount + 1);
  468.         _lineHeights[_heightCount] = height;
  469.         _heightCount++;
  470.  
  471.         _baselines = _growArrayTo(_baselines, _baselineCount + 1);
  472.         _baselines[_baselineCount] = baseline;
  473.         _baselineCount++;
  474.     }
  475.  
  476.     void _addLineRemainder(int width) {
  477.         int     i, count;
  478.  
  479.         if (width < 0) {
  480.             width = 0;
  481.         }
  482.  
  483.         _lineRemainders = _growArrayTo(_lineRemainders, _remainderCount + 1);
  484.         _lineRemainders[_remainderCount] = width;
  485.         _remainderCount++;
  486.     }
  487.  
  488.     int addWidthOfInitialTabs(int offsetX) {
  489.         TextStyleRun run;
  490.         int i,c,j,d;
  491.         FastStringBuffer rString;
  492.         int tabCount = 0;
  493.         int tabPositions[] = currentParagraphFormat().tabPositions();
  494.  
  495.         for(i=0,c=_runVector.count() ; i < c ; i++ ) {
  496.             run = (TextStyleRun) _runVector.elementAt(i);
  497.             rString = run._contents;
  498.             if( rString == null || rString.length() == 0 )
  499.                 break;
  500.             j=0;
  501.             d=rString.length();
  502.             while(j < d && rString.charAt(j) == '\t') {
  503.                 tabCount++;
  504.                 j++;
  505.             }
  506.             if( j < d )
  507.                 break;
  508.         }
  509.  
  510.         if( tabCount == 0 )
  511.             return offsetX;
  512.         else {
  513.             for(i=0,c=tabPositions.length ; i < c ; i++ )
  514.                 if( tabPositions[i] >= offsetX )
  515.                     break;
  516.             if( i == c )
  517.                 return offsetX;
  518.             else {
  519.                 i += tabCount;
  520.                 if( i >= tabPositions.length )
  521.                     return tabPositions[tabPositions.length-1];
  522.                 else
  523.                     return tabPositions[i-1];
  524.             }
  525.         }
  526.     }
  527.  
  528.     void computeLineBreaksAndHeights(int maxWidth) {
  529.       computeLineBreaksAndHeights(maxWidth,0);
  530.     }
  531.  
  532.     void computeLineBreaksAndHeights(int maxWidth,int fromLine) {
  533.         int debugOrigMaxWidth = maxWidth;
  534.         TextStyleRun    nextRun;
  535.         int             count, i, runCharsUsed, totalCharsInRun,
  536.                         charactersAddedToLine,
  537.                         remainingWidth, currentCharNumber, currentLineHeight,
  538.                         currentLineBaseline, startingWidth, ascenderHeight,
  539.                         descenderHeight, newAscenderHeight, newDescenderHeight,
  540.                         currentX,initialCurrentX;
  541.         TextParagraphFormat format = currentParagraphFormat();
  542.  
  543.         if(fromLine > 0)
  544.           fromLine--;
  545.  
  546.       /* clear line breaks */
  547.         _breakCount = fromLine;
  548.  
  549.       /* clear line heights and baselines */
  550.         _heightCount = fromLine;
  551.         _baselineCount = fromLine;
  552.  
  553.       /* clear line remainders */
  554.         _remainderCount = fromLine;
  555.         if (format._justification == Graphics.LEFT_JUSTIFIED && fromLine == 0) {
  556.             _lineRemainders = null;
  557.         }
  558.  
  559.         maxWidth -= format._leftMargin + format._rightMargin;
  560.         if (maxWidth < 1) {
  561.             maxWidth = 1;
  562.         }
  563.  
  564.       /*
  565.        * remainingWidth is the remaining space on the current line;
  566.        * at the start, it's just the total available space; normally, it's
  567.        * just maxWidth, but the leftIndent changes it for the first line
  568.        */
  569.         if(fromLine == 0) {
  570.           remainingWidth = maxWidth - format._leftIndent;
  571.           if (remainingWidth < 1) {
  572.             remainingWidth = 1;
  573.           }
  574.           startingWidth = remainingWidth;
  575.           _height = 0;
  576.           _charCount = 0;
  577.         } else {
  578.           remainingWidth = maxWidth;
  579.           startingWidth = maxWidth;
  580.           _height = 0;
  581.           for(i=0; i < fromLine ; i++)
  582.             _height += _lineHeights[i];
  583.           _charCount = _lineBreaks[fromLine-1];
  584.         }
  585.  
  586.  
  587.       /* start laying out each run */
  588.         count = _runVector.count();
  589.         currentCharNumber = _charCount;
  590.         currentLineHeight = 0;
  591.         currentLineBaseline = 0;
  592.         ascenderHeight = descenderHeight = 0;
  593.         currentX = format._leftMargin;
  594.         initialCurrentX = currentX;
  595.         if(fromLine == 0)
  596.           currentX += format._leftIndent;
  597.         if(format.wrapsUnderFirstCharacter() ) {
  598.             initialCurrentX = addWidthOfInitialTabs(format._leftMargin + format._leftIndent);
  599.             maxWidth -= (initialCurrentX - currentX);
  600.             remainingWidth = maxWidth;
  601.         }
  602.         if(fromLine == 0) {
  603.           i = 0;
  604.           nextRun = null;
  605.           totalCharsInRun = 0;
  606.           runCharsUsed = 0;
  607.         } else {
  608.           nextRun = runForCharPosition(_startChar + _charCount);
  609.           i = _runVector.indexOfIdentical(nextRun) + 1;
  610.           totalCharsInRun = nextRun.charCount();
  611.           runCharsUsed = _startChar + _charCount - nextRun.rangeIndex();
  612.           _charCount += (nextRun.rangeIndex() + totalCharsInRun -
  613.                          (_startChar + _charCount));
  614.         }
  615.         while(true)  {
  616.             if(nextRun == null || runCharsUsed >= totalCharsInRun) {
  617.                 if(i == _runVector.count())
  618.                     break;
  619.                 nextRun = (TextStyleRun)_runVector.elementAt(i++);
  620.                 if( nextRun.charCount() == 0 )
  621.                     continue;
  622.  
  623.                 runCharsUsed = 0;
  624.                 totalCharsInRun = nextRun.charCount();
  625.                 _charCount += totalCharsInRun;
  626.             }
  627.  
  628.           /* lay out characters until we run out */
  629.             while (runCharsUsed < totalCharsInRun) {
  630.               /* how many chars can fit in the available space? */
  631.                 charactersAddedToLine = nextRun.charsForWidth(runCharsUsed,
  632.                                                               currentX,
  633.                                                               remainingWidth,
  634.                                                               startingWidth,
  635.                                                             format._tabStops);
  636.  
  637.               /* if characters added, adjust markers */
  638.                 if (charactersAddedToLine > 0) {
  639.                     runCharsUsed += charactersAddedToLine;
  640.                     currentCharNumber += charactersAddedToLine;
  641.  
  642.                     newAscenderHeight = nextRun.baseline();
  643.                     newDescenderHeight = nextRun.height() - nextRun.baseline();
  644.  
  645.                     if (ascenderHeight < newAscenderHeight) {
  646.                         ascenderHeight = newAscenderHeight;
  647.                     }
  648.                     if (descenderHeight < newDescenderHeight) {
  649.                         descenderHeight = newDescenderHeight;
  650.                     }
  651.  
  652.                     if (ascenderHeight + descenderHeight > currentLineHeight) {
  653.                         currentLineHeight = ascenderHeight + descenderHeight;
  654.                     }
  655.                     if (ascenderHeight > currentLineBaseline) {
  656.                         currentLineBaseline = ascenderHeight;
  657.                     }
  658.  
  659.                     currentX += remainingWidth - nextRun._remainder;
  660.                     remainingWidth = nextRun._remainder;
  661.                 }
  662.  
  663.               /* wrap remaining characters to next line */
  664.                 if (runCharsUsed < totalCharsInRun) {
  665.                   /* place them on the next line */
  666.                     _addLineBreak(currentCharNumber);
  667.                     _addLineHeightAndBaseline(
  668.                                 currentLineHeight + format._lineSpacing,
  669.                                 currentLineBaseline);
  670.                     _height += currentLineHeight + format._lineSpacing;
  671.                     _addLineRemainder(remainingWidth);
  672.  
  673.                     remainingWidth = startingWidth = maxWidth;
  674.                     currentLineHeight = currentLineBaseline = 0;
  675.                     ascenderHeight = descenderHeight = 0;
  676.                     currentX = initialCurrentX;
  677.                     continue;
  678.                 }
  679.             }
  680.         }
  681.  
  682.       /* break at the end of the paragraph */
  683.         _addLineBreak(currentCharNumber);
  684.         if (currentLineHeight == 0) {
  685.             nextRun = (TextStyleRun)_runVector.firstElement();
  686.             currentLineHeight = nextRun.height() + format._lineSpacing;
  687.             currentLineBaseline = nextRun.baseline();
  688.         } else {
  689.             currentLineHeight += format._lineSpacing;
  690.         }
  691.         _addLineHeightAndBaseline(currentLineHeight, currentLineBaseline);
  692.         _height += currentLineHeight;
  693.         _addLineRemainder(remainingWidth);
  694.  
  695.         /* return char */
  696.         _charCount++;
  697.  
  698.         /*      if(fromLine>0) {
  699.              dumpMe();
  700.              computeLineBreaksAndHeights(debugOrigMaxWidth,0);
  701.              dumpMe();
  702.         } */
  703.     }
  704.  
  705. /**  String dumpMe() {
  706.         int i;
  707.         StringBuffer sb = new StringBuffer();
  708.         sb.append("RunVector is " + _runVector +
  709.                   " _y=" + _y +
  710.                   " _height=" + _height +
  711.                   " _breakCount=" + _breakCount +
  712.                   " _charCount=" + _charCount);
  713.  
  714.         sb.append("line breaks:");
  715.         for(i=0;i<_breakCount;i++)
  716.             sb.append("" + _lineBreaks[i] + " ");
  717.         sb.append("");
  718.  
  719.         sb.append("line heights:");
  720.         for(i=0;i<_breakCount;i++)
  721.             sb.append("" + _lineHeights[i] + " ");
  722.         sb.append("");
  723.             return sb.toString();
  724.      } **/
  725.  
  726.  
  727.      int characterStartingLine(int lineNumber) {
  728.         if( lineNumber == 0 )
  729.             return _startChar;
  730.         else if( lineNumber < _breakCount )
  731.             return _startChar + _lineBreaks[lineNumber-1];
  732.         else
  733.             return -1;
  734.     }
  735.  
  736.      Rect rectForLine(int lineNumber) {
  737.         int     currentX, currentY, i;
  738.         TextParagraphFormat f = currentParagraphFormat();
  739.  
  740.         if (lineNumber >= _breakCount) {
  741.             return null;
  742.         }
  743.  
  744.         currentY = _y;
  745.         for (i = 0; i < lineNumber; i++) {
  746.             currentY += _lineHeights[i];
  747.         }
  748.  
  749.         return TextView.newRect(f._leftMargin, currentY,
  750.                                 _owner.bounds.width - f._rightMargin, _lineHeights[i]);
  751.     }
  752.  
  753.     Range rangeForLine(int lineNumber) {
  754.         int start,end;
  755.         if( lineNumber >= _breakCount )
  756.             return new Range(_startChar + _charCount , 0);
  757.  
  758.         if( lineNumber == 0 )
  759.             return new Range(_startChar,_lineBreaks[lineNumber]/*(+_startChar - _startChar)*/);
  760.         else
  761.             return new Range(_startChar + _lineBreaks[lineNumber-1],
  762.                              _lineBreaks[lineNumber]-_lineBreaks[lineNumber-1]);
  763.     }
  764.  
  765.   int runIndexForCharPosition(int absPosition) {
  766.     TextStyleRun    nextRun;
  767.     int             position, count, i;
  768.  
  769.     position = absPosition - _startChar;
  770.     count = _runVector.count();
  771.  
  772.     for (i = 0; i < count; i++) {
  773.       nextRun = (TextStyleRun)_runVector.elementAt(i);
  774.  
  775.       if (nextRun.charCount() <= position) {
  776.         position -= nextRun.charCount();
  777.         continue;
  778.       }
  779.  
  780.       return i;
  781.     }
  782.  
  783.     return _runVector.count() - 1;
  784.   }
  785.  
  786.   TextStyleRun runForCharPosition(int absPosition) {
  787.     int index = runIndexForCharPosition(absPosition);
  788.     if(index >= 0)
  789.       return (TextStyleRun) _runVector.elementAt(index);
  790.     else
  791.       return null;
  792.   }
  793.  
  794.      char characterAt(int absPosition) {
  795.         TextStyleRun    nextRun;
  796.         char            theChar;
  797.         int             position, count, i;
  798.  
  799.         if (_charCount < 2) {
  800.             return '\n';
  801.         }
  802.  
  803.         position = absPosition - _startChar;
  804.  
  805.         count = _runVector.count();
  806.         for (i = 0; i < count; i++) {
  807.             nextRun = (TextStyleRun)_runVector.elementAt(i);
  808.  
  809.             if (nextRun.charCount() <= position) {
  810.                 position -= nextRun.charCount();
  811.                 continue;
  812.             }
  813.  
  814.             theChar = nextRun.charAt(position);
  815.  
  816.             return theChar;
  817.         }
  818.  
  819.       /* this is the return character */
  820.         if (position < 2) {
  821.             return '\n';
  822.         }
  823.  
  824.         return '\0';
  825.     }
  826.  
  827.      int lineForPosition(int absPosition) {
  828.         int     position, i;
  829.  
  830.         position = absPosition - _startChar;
  831.  
  832.       /* if return character, return the last line */
  833.         if (_breakCount > 0 && position == _lineBreaks[_breakCount - 1]) {
  834.             return _breakCount - 1;
  835.         }
  836.  
  837.         for (i = 0; i < _breakCount && position >= _lineBreaks[i]; i++) {
  838.         }
  839.  
  840.         if (i >= _breakCount) {
  841.             return -1;
  842.         }
  843.  
  844.         return i;
  845.     }
  846.  
  847.     /* If absolute is false, this method will return the next character
  848.      * if the hit point is on the right of the glyph center. Otherwise
  849.      * it will return the character for the glyph.
  850.      * Example:  Netscape
  851.      * flag is false, (x,y) is on the 't' a little after the center.
  852.      *     the returned position will be the position of s.
  853.      * flag is true , (x,y) is on the 't' a little after the center.
  854.      *     the returned position will be the position of t
  855.      */
  856.      TextPositionInfo positionForPoint(int x, int y,boolean absolute) {
  857.         TextStyleRun            nextRun = null;
  858.         TextPositionInfo        currentInfo, previousInfo = null,
  859.                                 endPosition;
  860.         int                     i, currentY, firstChar, lastChar, charCount,
  861.                                 currentPosition, previousPosition, remainder,
  862.                                 currentX, availableWidth, lineNumber,
  863.                                 runIndex, deltaX, runStartChar = 0, count;
  864.         TextParagraphFormat format = currentParagraphFormat();
  865.  
  866.       /* which line is it on? */
  867.  
  868.  
  869.         currentY = _y;
  870.         for (i = 0; i < _breakCount; i++) {
  871.             if (y >= currentY && y <= currentY + _lineHeights[i]) {
  872.                 break;
  873.             }
  874.             currentY += _lineHeights[i];
  875.         }
  876.  
  877.         lineNumber = i;
  878.         if (lineNumber == 0) {
  879.             firstChar = _startChar;
  880.         } else {
  881.             firstChar = _startChar + _lineBreaks[lineNumber - 1];
  882.         }
  883.         lastChar = _startChar + _lineBreaks[lineNumber];
  884.  
  885.       /* find the run that begins the line */
  886.         count = _runVector.count();
  887.         charCount = _startChar;
  888.         for (i = 0; i < count; i++) {
  889.             nextRun = (TextStyleRun)_runVector.elementAt(i);
  890.             if (charCount + nextRun.charCount() > firstChar) {
  891.                 runStartChar = firstChar - charCount;
  892.                 break;
  893.             }
  894.             charCount += nextRun.charCount();
  895.         }
  896.         if (nextRun == null) {
  897.             return null;
  898.         }
  899.         runIndex = i;
  900.  
  901.         if (format._justification == Graphics.LEFT_JUSTIFIED) {
  902.             currentX = format._leftMargin;
  903.         } else if (format._justification ==
  904.                                     Graphics.RIGHT_JUSTIFIED) {
  905.             currentX = format._leftMargin +
  906.                        _lineRemainders[lineNumber];
  907.         } else {
  908.             currentX = format._leftMargin +
  909.                        _lineRemainders[lineNumber] / 2;
  910.         }
  911.         availableWidth = _owner.bounds.width - format._leftMargin -
  912.                          format._rightMargin;
  913.         if (lineNumber == 0) {
  914.             currentX += format._leftIndent;
  915.             availableWidth -= format._leftIndent;
  916.         } else if( format.wrapsUnderFirstCharacter()) {
  917.             int oldCurrentX = currentX;
  918.             currentX = addWidthOfInitialTabs( currentX + format._leftIndent);
  919.             availableWidth -= (currentX - oldCurrentX);
  920.         }
  921.         if (availableWidth < 1) {
  922.             availableWidth = 1;
  923.         }
  924.  
  925.       /* beyond ends of line? */
  926.         if (x > (currentX + availableWidth - _lineRemainders[lineNumber])) {
  927.             endPosition = infoForPosition(lastChar, -1);
  928.             endPosition.setAtEndOfLine(true);
  929.             return endPosition;
  930.         } else if (x <= currentX) {
  931.             return infoForPosition(firstChar, y);
  932.         }
  933.  
  934.         runIndex++;
  935.         while(nextRun != null && nextRun.charCount() == 0 ) {
  936.             nextRun = runAfter(nextRun);
  937.             runIndex++;
  938.         }
  939.         if( nextRun == null ) {
  940.             return infoForPosition(firstChar + charCount,y);
  941.         }
  942.         while (firstChar <= lastChar) {
  943.             deltaX = nextRun.widthOfContents(runStartChar, 1, currentX,
  944.                                              format._tabStops);
  945.             if (x >= currentX && x <= (currentX + deltaX)) {
  946.                 if( absolute )
  947.                     return infoForPosition(firstChar,y);
  948.                 else {
  949.                     deltaX /= 2;
  950.                     if (x >= currentX + deltaX) {
  951.                         return infoForPosition(firstChar + 1, y);
  952.                     }
  953.                     return infoForPosition(firstChar, y);
  954.                 }
  955.             }
  956.  
  957.             runStartChar++;
  958.             if (runStartChar >= nextRun.charCount()) {
  959.                 nextRun = (TextStyleRun)objectAt(_runVector, runIndex++);
  960.                 while(nextRun != null && nextRun.charCount() == 0 ) {
  961.                     nextRun = runAfter(nextRun);
  962.                     runIndex++;
  963.                 }
  964.                 if (nextRun == null) {
  965.                     return infoForPosition(firstChar + charCount, y);
  966.                 }
  967.                 runStartChar = 0;
  968.             }
  969.  
  970.             firstChar++;
  971.             currentX += deltaX;
  972.         }
  973.  
  974.         return null;
  975.     }
  976.  
  977.     TextPositionInfo _infoForPosition(int absPosition) {
  978.         TextStyleRun    nextRun;
  979.         int             position, i=0, charCount = 0, runNumber = 1, currentX=0,
  980.                         currentY, runChars, deltaX = 0, runStartChar,initialPosition,
  981.                         maxWidth, availableWidth;
  982.         TextParagraphFormat format = currentParagraphFormat();
  983.         position = absPosition - _startChar;
  984.         initialPosition = position;
  985.  
  986.         if(position >= _charCount)
  987.             position = _charCount;
  988.  
  989.         maxWidth = _owner.bounds.width - format._leftMargin -
  990.                    format._rightMargin;
  991.         currentY = _y;
  992.  
  993.         for(i=0;i<(_breakCount-1);i++) {
  994.             if(_lineBreaks[i] < position) {
  995.               currentY += _lineHeights[i];
  996.             } else
  997.               break;
  998.         }
  999.  
  1000.         if(i > 0) {
  1001.             runNumber = runIndexForCharPosition(_startChar + _lineBreaks[i-1]);
  1002.             nextRun = (TextStyleRun) _runVector.elementAt(runNumber++);
  1003.             runStartChar = _lineBreaks[i-1] + _startChar - nextRun.rangeIndex();
  1004.             position -= _lineBreaks[i-1];
  1005.         } else {
  1006.             runNumber = 1;
  1007.             nextRun = (TextStyleRun)_runVector.firstElement();
  1008.             runStartChar = 0;
  1009.         }
  1010.  
  1011.         for (; i < _breakCount; i++) {
  1012.             if (i == 0) {
  1013.                 charCount = _lineBreaks[i];
  1014.             } else {
  1015.                 charCount = _lineBreaks[i] - _lineBreaks[i - 1];
  1016.             }
  1017.  
  1018.             if (charCount > position) {
  1019.                 charCount = position;
  1020.             }
  1021.  
  1022.             if (format._justification == Graphics.LEFT_JUSTIFIED) {
  1023.                 currentX = format._leftMargin;
  1024.             } else if (format._justification ==
  1025.                                         Graphics.RIGHT_JUSTIFIED) {
  1026.                 currentX = format._leftMargin +
  1027.                            _lineRemainders[i];
  1028.             } else {
  1029.                 currentX = format._leftMargin +
  1030.                            _lineRemainders[i] / 2;
  1031.             }
  1032.  
  1033.             availableWidth = maxWidth;
  1034.             if (i == 0) {
  1035.                 currentX += format._leftIndent;
  1036.                 availableWidth -= format._leftIndent;
  1037.             }  else if( format.wrapsUnderFirstCharacter()) {
  1038.                 int newCurrentX = addWidthOfInitialTabs( currentX + format._leftIndent);
  1039.                 availableWidth -= (newCurrentX - currentX);
  1040.                 currentX = newCurrentX;
  1041.             }
  1042.             if (availableWidth < 1) {
  1043.                 availableWidth = 1;
  1044.             }
  1045.  
  1046.             if (charCount == 0) {
  1047.                 return new TextPositionInfo(nextRun, currentX, currentY, i,
  1048.                                             _lineHeights[i], runStartChar,
  1049.                                             absPosition);
  1050.             }
  1051.  
  1052.             while (charCount > 0) {
  1053.                 runChars = nextRun.charCount() - runStartChar;
  1054.  
  1055.                 if (charCount >= runChars) {
  1056.                     if (charCount <= position) {
  1057.                         deltaX = nextRun.widthOfContents(runStartChar,
  1058.                                                          charCount, currentX,
  1059.                                                          format._tabStops);
  1060.                     }
  1061.                     charCount -= runChars;
  1062.                     position -= runChars;
  1063.  
  1064.                     nextRun = (TextStyleRun)objectAt(_runVector, runNumber++);
  1065.                     while (nextRun != null && nextRun.charCount() == 0) {
  1066.                         nextRun = (TextStyleRun)objectAt(_runVector,
  1067.                                                                 runNumber++);
  1068.                     }
  1069.                     runStartChar = 0;
  1070.                 } else {
  1071.                     if (charCount <= position) {
  1072.                         deltaX = nextRun.widthOfContents(runStartChar,
  1073.                                                          charCount, currentX,
  1074.                                                          format._tabStops);
  1075.                     }
  1076.  
  1077.                     runStartChar += charCount;
  1078.                     position -= charCount;
  1079.                     charCount = 0;
  1080.                 }
  1081.                 currentX += deltaX;
  1082.                 availableWidth -= deltaX;
  1083.  
  1084.                 if (position == 0 ||
  1085.                     (nextRun == null && position == 1)) {
  1086.                     TextPositionInfo result;
  1087.                     if (nextRun == null) {
  1088.                         nextRun = (TextStyleRun)_runVector.lastElement();
  1089.                         runStartChar = nextRun.charCount();
  1090.                     }
  1091.                     result = new TextPositionInfo(nextRun, currentX, currentY, i,
  1092.                                                 _lineHeights[i], runStartChar,
  1093.                                                 absPosition);
  1094.                     if( initialPosition == _lineBreaks[i] ) {
  1095.                         result.setAtEndOfLine(true);
  1096.                         if( i == (_breakCount-1))
  1097.                           result.setAtEndOfParagraph(true);
  1098.                     }
  1099.                     return result;
  1100.  
  1101.                 }
  1102.             }
  1103.  
  1104.             currentY += _lineHeights[i];
  1105.         }
  1106.         return null;
  1107.     }
  1108.  
  1109.   /* yCoord == -1 ignores special fudging */
  1110.     TextPositionInfo infoForPosition(int absPosition, int yCoord) {
  1111.         TextPositionInfo        positionInfo, nextInfo;
  1112.         int                     lineNumber, currentX;
  1113.         TextParagraphFormat format = currentParagraphFormat();
  1114.  
  1115.         positionInfo = _infoForPosition(absPosition);
  1116.  
  1117.         /* If positionInfo out of bounds, return the last position */
  1118.         if( positionInfo == null ) {
  1119.             positionInfo = _infoForPosition(_startChar + _charCount);
  1120.             return positionInfo;
  1121.         }
  1122.  
  1123.         if (yCoord < positionInfo.maxY()) {
  1124.           return positionInfo;
  1125.         }
  1126.  
  1127.       /* if not at end of line, we're done */
  1128.         nextInfo = _infoForPosition(absPosition + 1);
  1129.         if (nextInfo == null ||
  1130.             nextInfo._lineNumber == positionInfo._lineNumber) {
  1131.             return positionInfo;
  1132.         }
  1133.  
  1134.         lineNumber = nextInfo._lineNumber;
  1135.         if (format._justification == Graphics.LEFT_JUSTIFIED) {
  1136.             currentX = format._leftMargin;
  1137.         } else if (format._justification ==
  1138.                                     Graphics.RIGHT_JUSTIFIED) {
  1139.             currentX = format._leftMargin +
  1140.                        _lineRemainders[lineNumber];
  1141.         } else {
  1142.             currentX = format._leftMargin +
  1143.                        _lineRemainders[lineNumber] / 2;
  1144.         }
  1145.  
  1146.       /*
  1147.        * create a TextInfo that represents the absPosition at the start of the
  1148.        * next line, rather than the end of the one previous
  1149.        */
  1150.         positionInfo = new TextPositionInfo(positionInfo._textRun, currentX,
  1151.                                             nextInfo._y, nextInfo._lineNumber,
  1152.                                             nextInfo._lineHeight,
  1153.                                             positionInfo._positionInRun,
  1154.                                             positionInfo._absPosition);
  1155.         positionInfo.setNextLine(true);
  1156.  
  1157.         return positionInfo;
  1158.     }
  1159.  
  1160.      TextPositionInfo insertCharOrStringAt(char aChar, String aString,
  1161.                                                  int absPosition) {
  1162.         TextPositionInfo        lastCharPosition, newPosition,
  1163.                                 newLastCharPosition;
  1164.         TextStyleRun            nextRun = null, newRun;
  1165.         int                     i, count, position, currentLine, charCount,
  1166.                                 lastCharNumber, oldHeight;
  1167.  
  1168.         if (aString == null && aChar == '\0') {
  1169.             return null;
  1170.         }
  1171.  
  1172.         /* find the run that has this character */
  1173.         position = absPosition - _startChar;
  1174.         count = _runVector.count();
  1175.         for (i = 0; i < count; i++) {
  1176.             nextRun = (TextStyleRun)objectAt(_runVector, i);
  1177.  
  1178.             if (nextRun == null) {
  1179.                 break;
  1180.             }
  1181.  
  1182.             if (nextRun.charCount() < position) {
  1183.                 position -= nextRun.charCount();
  1184.                 continue;
  1185.             }
  1186.  
  1187.             if (nextRun.containsATextAttachment()) {
  1188.                 if (position == 0) {
  1189.                     /* ALERT! Should create a run with the attributes of the previous run */
  1190.                     newRun = nextRun.createEmptyRun();
  1191.                     insertRunAt(newRun, _runVector.indexOfIdentical(nextRun));
  1192.                     nextRun = newRun;
  1193.                 } else {
  1194.                     TextStyleRun previousRun = null;
  1195.                     if( i > 0 ) {
  1196.                         previousRun = (TextStyleRun) objectAt(_runVector,i-1);
  1197.                         newRun = previousRun.createEmptyRun(
  1198.                               TextView.attributesByRemovingStaticAttributes(previousRun.attributes()));
  1199.                         insertRunAt(newRun,_runVector.indexOfIdentical(nextRun) + 1);
  1200.                         nextRun = newRun;
  1201.                     } else {
  1202.                         /** We should filter static attributes here too */
  1203.                         nextRun = (TextStyleRun)objectAt(_runVector, 0);
  1204.                         newRun = nextRun.createEmptyRun(
  1205.                               TextView.attributesByRemovingStaticAttributes(nextRun.attributes()));
  1206.                         insertRunAt(newRun,1);
  1207.                         nextRun = newRun;
  1208.                     }
  1209.                     if (nextRun == null) {
  1210.                         /* ALERT! Should create a run with the attributes of the previous run */
  1211.                         nextRun = new TextStyleRun(this, "",null);
  1212.                         addRun(nextRun);
  1213.                     }
  1214.                 }
  1215.                 position = 0;
  1216.             }
  1217.  
  1218.             break;
  1219.         }
  1220.  
  1221.         if ((i >= count || nextRun == null) && position == 1) {
  1222.           /* return character */
  1223.             nextRun = (TextStyleRun)_runVector.lastElement();
  1224.             position = nextRun.charCount();
  1225.         } else if (nextRun == null) {
  1226.             return null;
  1227.         }
  1228.  
  1229.         currentLine = lineForPosition(absPosition - 1);
  1230.         lastCharNumber = _lineBreaks[currentLine] + _startChar;
  1231.         lastCharPosition = infoForPosition(lastCharNumber, -1);
  1232.         oldHeight = _height;
  1233.  
  1234.         if (aString != null) {
  1235.             nextRun.insertStringAt(aString, position);
  1236.             charCount = aString.length();
  1237.         } else {
  1238.             nextRun.insertCharAt(aChar, position);
  1239.             charCount = 1;
  1240.         }
  1241.  
  1242.         computeLineBreaksAndHeights(_owner.bounds.width,currentLine);
  1243.  
  1244.         /* information about new insertion point position */
  1245.         newPosition = infoForPosition(absPosition + charCount, -1);
  1246.  
  1247.         if( oldHeight != _height ) {
  1248.             newPosition.setRedrawCurrentParagraphOnly(false);
  1249.             newPosition.setRedrawCurrentLineOnly(false);
  1250.             return newPosition;
  1251.         }
  1252.  
  1253.         newPosition.setRedrawCurrentParagraphOnly(true);
  1254.  
  1255.       /* did we jump to a different line? */
  1256.         if (newPosition._lineNumber != lastCharPosition._lineNumber) {
  1257.             newPosition.setRedrawCurrentParagraphOnly(false);
  1258.             if (lastCharPosition._lineNumber < newPosition._lineNumber) {
  1259.                 newPosition.setUpdateLine(lastCharPosition._lineNumber);
  1260.             } else {
  1261.                 newPosition.setUpdateLine(newPosition._lineNumber);
  1262.             }
  1263.  
  1264.             return newPosition;
  1265.         } else
  1266.             newPosition.setRedrawCurrentParagraphOnly(true);
  1267.  
  1268.       /* we're on the same line, but did the character at the end change? */
  1269.         newLastCharPosition = infoForPosition(lastCharNumber + 1, -1);
  1270.         if (newLastCharPosition != null && lastCharPosition != null &&
  1271.             newLastCharPosition._lineNumber == lastCharPosition._lineNumber) {
  1272.             if( currentParagraphFormat().wrapsUnderFirstCharacter() )
  1273.                 newPosition.setRedrawCurrentLineOnly(false);
  1274.             else
  1275.                 newPosition.setRedrawCurrentLineOnly(true);
  1276.         } else
  1277.             newPosition.setRedrawCurrentLineOnly(false);
  1278.  
  1279.         return newPosition;
  1280.     }
  1281.  
  1282.      TextPositionInfo removeCharAt(int absPosition) {
  1283.         TextPositionInfo        firstCharPosition, firstNextLineCharPosition,
  1284.                                 newPosition, newFirstCharPosition,
  1285.                                 newNextLineFirstCharPosition;
  1286.         TextStyleRun            nextRun = null;
  1287.         int                     i, count, position, currentLine,
  1288.                                 firstCharNumber, firstNextLineCharNumber,
  1289.                                 oldHeight;
  1290.  
  1291.         if (absPosition <= _startChar) {
  1292.             return null;
  1293.         }
  1294.         //ALERT! - THIS BUG WAS A JIT BUG!!
  1295. //        absPosition--;
  1296.         absPosition = absPosition - 1;
  1297.  
  1298.       /* find the run that has this character */
  1299.         position = absPosition - _startChar;
  1300.         count = _runVector.count();
  1301.         for (i = 0; i < count; i++) {
  1302.             nextRun = (TextStyleRun)_runVector.elementAt(i);
  1303.  
  1304.             if (nextRun.charCount() <= position) {
  1305.                 position -= nextRun.charCount();
  1306.                 continue;
  1307.             }
  1308.  
  1309.             break;
  1310.         }
  1311.  
  1312.         if ((i >= count || nextRun == null) && position == 0) {
  1313.           /* return character */
  1314.             nextRun = (TextStyleRun)_runVector.lastElement();
  1315.             position = nextRun.charCount() - 1;
  1316.         } else if (nextRun == null) {
  1317.             return null;
  1318.         }
  1319.  
  1320.         currentLine = lineForPosition(absPosition - 1);
  1321.         if (currentLine == 0) {
  1322.             firstCharNumber = _startChar + 1;
  1323.         } else {
  1324.             firstCharNumber = _lineBreaks[currentLine - 1] + _startChar + 1;
  1325.         }
  1326.         firstNextLineCharNumber = _lineBreaks[currentLine] + _startChar + 1;
  1327.         if (firstNextLineCharNumber > _startChar + _charCount) {
  1328.             firstNextLineCharNumber = _startChar + _charCount;
  1329.         }
  1330.         firstNextLineCharPosition = infoForPosition(firstNextLineCharNumber,
  1331.                                                     -1);
  1332.         firstCharPosition = infoForPosition(firstCharNumber, -1);
  1333.         oldHeight = _height;
  1334.  
  1335.         nextRun.removeCharAt(position);
  1336.         if (nextRun.charCount() == 0 && _runVector.count() > 1) {
  1337.             _runVector.removeElement(nextRun);
  1338.         }
  1339.         computeLineBreaksAndHeights(_owner.bounds.width);
  1340.  
  1341.       /* information about new insertion point position */
  1342.         newPosition = infoForPosition(absPosition, -1);
  1343.  
  1344.         if (oldHeight == _height) {
  1345.             newPosition.setRedrawCurrentParagraphOnly(true);
  1346.         }
  1347.  
  1348.       /* did we jump down a line? */
  1349.         if (newPosition._lineNumber != firstCharPosition._lineNumber) {
  1350.             if (firstCharPosition._lineNumber < newPosition._lineNumber) {
  1351.                 newPosition.setUpdateLine(firstCharPosition._lineNumber);
  1352.             } else {
  1353.                 newPosition.setUpdateLine(newPosition._lineNumber);
  1354.             }
  1355.  
  1356.             return newPosition;
  1357.         }
  1358.  
  1359.       /* did part of the next line come up? */
  1360.         newNextLineFirstCharPosition = infoForPosition(
  1361.                                             firstNextLineCharNumber - 1, -1);
  1362.  
  1363.         if (firstNextLineCharPosition._lineNumber !=
  1364.             newNextLineFirstCharPosition._lineNumber) {
  1365.             if (firstNextLineCharPosition._lineNumber <
  1366.                 newNextLineFirstCharPosition._lineNumber) {
  1367.                 newPosition.setUpdateLine(
  1368.                                         firstNextLineCharPosition._lineNumber);
  1369.             } else {
  1370.                 newPosition.setUpdateLine(
  1371.                                     newNextLineFirstCharPosition._lineNumber);
  1372.             }
  1373.  
  1374.             return newPosition;
  1375.         }
  1376.  
  1377.       /* we're on the same line, but did the character at the end change? */
  1378.         newFirstCharPosition = infoForPosition(firstCharNumber, -1);
  1379.  
  1380.         if (oldHeight == _height &&
  1381.             newFirstCharPosition != null && firstCharPosition != null &&
  1382.            newFirstCharPosition._lineNumber == firstCharPosition._lineNumber) {
  1383.             if( currentParagraphFormat().wrapsUnderFirstCharacter())
  1384.                 newPosition.setRedrawCurrentLineOnly(false);
  1385.             else
  1386.                 newPosition.setRedrawCurrentLineOnly(true);
  1387.         }
  1388.  
  1389.         return newPosition;
  1390.     }
  1391.  
  1392.     TextStyleRun createNewRunAt(int absPosition) {
  1393.         TextPositionInfo        breakPosition;
  1394.         TextStyleRun            newRun;
  1395.         int                     position;
  1396.  
  1397.         breakPosition = infoForPosition(absPosition, -1);
  1398.         if (breakPosition == null) {
  1399.             return null;
  1400.         }
  1401.  
  1402.         position = _runVector.indexOfIdentical(breakPosition._textRun);
  1403.         newRun = breakPosition._textRun.breakAt(breakPosition._positionInRun);
  1404.         insertRunAt(newRun, position + 1);
  1405.         return newRun;
  1406.     }
  1407.  
  1408.  
  1409.   TextParagraph createNewParagraphAt(int absPosition) {
  1410.         TextParagraph           newParagraph;
  1411.         TextStyleRun            newRun = null, firstRun, previousRun;
  1412.         int                     position, count, i, runCount;
  1413.         TextParagraphFormat format = currentParagraphFormat();
  1414.         int positionInRun;
  1415.         TextStyleRun run;
  1416.  
  1417.         collectEmptyRuns();
  1418.  
  1419.         run = runForCharPosition( absPosition );
  1420.         positionInRun = absPosition - run.rangeIndex();
  1421.  
  1422.         newParagraph = new TextParagraph(_owner, format);
  1423.  
  1424.         if (positionInRun == 0) {
  1425.             Hashtable attr;
  1426.             i = _runVector.indexOfIdentical(run);
  1427.             attr = TextView.attributesByRemovingStaticAttributes(run.attributes());
  1428.             if (i == 0) {
  1429.                 newRun = run.createEmptyRun(attr);
  1430.                 _runVector.insertElementAt(newRun, 0);
  1431.             } else {
  1432.                 i--;
  1433.             }
  1434.             newParagraph.addRun( new TextStyleRun(this,"",attr));
  1435.  
  1436.         } else if (run.containsATextAttachment()) {
  1437.             int k;
  1438.             i = _runVector.indexOfIdentical(run);
  1439.             k = i-1;
  1440.             previousRun=null;
  1441.             while(k > 0) {
  1442.                 previousRun = (TextStyleRun)objectAt(_runVector, k);
  1443.                 if( previousRun == null )
  1444.                     break;
  1445.                 else if(! previousRun.containsATextAttachment())
  1446.                     break;
  1447.                 else
  1448.                     k--;
  1449.             }
  1450.  
  1451.             if (previousRun == null) {
  1452.                 newRun = new TextStyleRun(this,"",null);
  1453.                 newParagraph.addRun(newRun);
  1454.             } else {
  1455.                 newRun = new TextStyleRun(this, "", TextView.attributesByRemovingStaticAttributes(
  1456.                                                 previousRun.attributes()));
  1457.                 newParagraph.addRun(newRun);
  1458.             }
  1459.         } else {
  1460.             newRun = firstRun = run.breakAt(positionInRun);
  1461.             newParagraph.addRun(firstRun);
  1462.             i = _runVector.indexOfIdentical(run);
  1463.         }
  1464.  
  1465.         if (i < 0) {
  1466.             return newParagraph;
  1467.         }
  1468.         i++;
  1469.  
  1470.         count = _runVector.count();
  1471.         runCount = 0;
  1472.         for (; i < count; i++, runCount++) {
  1473.             newParagraph.addRun((TextStyleRun)_runVector.elementAt(i));
  1474.         }
  1475.         while (runCount-- > 0) {
  1476.             _runVector.removeLastElement();
  1477.         }
  1478.  
  1479.         return newParagraph;
  1480.     }
  1481.  
  1482.     void drawBackgroundForLine(Graphics g, int lineNumber, int currentX,
  1483.                               int currentY) {
  1484.         TextPositionInfo        startInfo, endInfo;
  1485.         Rect                    selectionRect = null, nonSelectionRect,
  1486.                                 nonSelectionRect2;
  1487.         int                     selectionStart, selectionEnd, maxWidth,defaultMaxWidth,
  1488.                                 lineStartCharNumber, lineEndCharNumber;
  1489.  
  1490.         TextParagraphFormat format = currentParagraphFormat();
  1491.         TextParagraphFormat defaultFormat = (TextParagraphFormat)
  1492.             _owner.defaultAttributes().get(TextView.PARAGRAPH_FORMAT_KEY);
  1493.  
  1494.  
  1495.         maxWidth = _owner.bounds.width - format._leftMargin -
  1496.                    format._rightMargin;
  1497.         defaultMaxWidth = _owner.bounds.width - defaultFormat._leftMargin -
  1498.                    defaultFormat._rightMargin;
  1499.  
  1500.         if (lineNumber == 0) {
  1501.             maxWidth -= format._leftIndent;
  1502.         }
  1503.  
  1504.         if (lineNumber < 0 || lineNumber >= _breakCount ||
  1505.             (!_owner.hasSelectionRange() && !_owner.insertionPointVisible)) {
  1506.             if (!_owner.isTransparent()) {
  1507.                 g.setColor(_owner._backgroundColor);
  1508.                 g.fillRect(defaultFormat._leftMargin, currentY, defaultMaxWidth,
  1509.                            _lineHeights[lineNumber]);
  1510.             }
  1511.             return;
  1512.         }
  1513.  
  1514.         selectionStart = _owner.selectionStart();
  1515.         selectionEnd = _owner.selectionEnd();
  1516.         startInfo = _owner.selectionStartInfo();
  1517.         endInfo = _owner.selectionEndInfo();
  1518.  
  1519.         if (lineNumber == 0) {
  1520.             lineStartCharNumber = _startChar;
  1521.         } else {
  1522.             lineStartCharNumber = _startChar + _lineBreaks[lineNumber - 1];
  1523.         }
  1524.         lineEndCharNumber = _startChar + _lineBreaks[lineNumber];
  1525.         if (lineNumber == _breakCount - 1) {
  1526.             lineEndCharNumber++;
  1527.         }
  1528.  
  1529.         if (selectionStart == selectionEnd || selectionStart > lineEndCharNumber ||
  1530.             selectionEnd < lineStartCharNumber) {
  1531.             if (!_owner.isTransparent()) {
  1532.                 g.setColor(_owner._backgroundColor);
  1533.                 g.fillRect(defaultFormat._leftMargin, currentY, defaultMaxWidth,
  1534.                            _lineHeights[lineNumber]);
  1535.             }
  1536.             return;
  1537.         }
  1538.  
  1539.         if (lineStartCharNumber >= selectionStart &&
  1540.             lineEndCharNumber <= selectionEnd) {
  1541.           /* all characters on this line selected */
  1542.             selectionRect = TextView.newRect(defaultFormat._leftMargin,currentY,defaultMaxWidth,
  1543.                                              _lineHeights[lineNumber]);
  1544.             nonSelectionRect = nonSelectionRect2 = null;
  1545.         } else if (lineStartCharNumber >= selectionStart &&
  1546.                    lineEndCharNumber > selectionEnd &&
  1547.                    lineStartCharNumber < selectionEnd) {
  1548.           /* first through some # selected on this line */
  1549.             if( selectionStart == lineStartCharNumber ) {
  1550.                 selectionRect = TextView.newRect(currentX, currentY,
  1551.                                                  endInfo._x - currentX,
  1552.                                                  _lineHeights[lineNumber]);
  1553.             } else {
  1554.                 selectionRect = TextView.newRect(defaultFormat._leftMargin,currentY,
  1555.                                                  endInfo._x - defaultFormat._leftMargin,
  1556.                                                  _lineHeights[lineNumber]);
  1557.             }
  1558.  
  1559.             nonSelectionRect = TextView.newRect(selectionRect.maxX(), currentY,
  1560.                                                 defaultMaxWidth - selectionRect.width,
  1561.                                                 _lineHeights[lineNumber]);
  1562.  
  1563.             nonSelectionRect2 = null;
  1564.         } else if (lineStartCharNumber < selectionStart && selectionStart < lineEndCharNumber &&
  1565.                    lineEndCharNumber <= selectionEnd) {
  1566.           /* some # through last selected on this line */
  1567.             if (startInfo._textRun._paragraph != this ||
  1568.                 startInfo._lineNumber > lineNumber) {
  1569.                 nonSelectionRect = TextView.newRect(defaultFormat._leftMargin, currentY,
  1570.                                                     defaultMaxWidth,
  1571.                                                     _lineHeights[lineNumber]);
  1572.             } else {
  1573.             selectionRect = TextView.newRect(startInfo._x, currentY,
  1574.                                              _owner.bounds.width - defaultFormat._rightMargin -
  1575.                                              startInfo._x, _lineHeights[lineNumber]);
  1576.             nonSelectionRect = TextView.newRect(defaultFormat._leftMargin, currentY,
  1577.                                             selectionRect.x - defaultFormat._leftMargin,
  1578.                                             _lineHeights[lineNumber]);
  1579.             }
  1580.             nonSelectionRect2 = null;
  1581.         } else if (lineStartCharNumber < selectionStart &&
  1582.                    lineEndCharNumber > selectionEnd) {
  1583.           /* entire selection is a subrange of characters on this line */
  1584.             selectionRect = TextView.newRect(startInfo._x, currentY,
  1585.                                          endInfo._x - startInfo._x,
  1586.                                          _lineHeights[lineNumber]);
  1587.             nonSelectionRect = TextView.newRect(selectionRect.maxX(), currentY,
  1588.                                             defaultMaxWidth - selectionRect.width,
  1589.                                             _lineHeights[lineNumber]);
  1590.             nonSelectionRect2 = TextView.newRect(defaultFormat._leftMargin, currentY,
  1591.                                              selectionRect.x - defaultFormat._leftMargin,
  1592.                                              _lineHeights[lineNumber]);
  1593.         } else {
  1594.             nonSelectionRect = TextView.newRect(defaultFormat._leftMargin, currentY, defaultMaxWidth,
  1595.                                                 _lineHeights[lineNumber]);
  1596.             nonSelectionRect2 = null;
  1597.         }
  1598.  
  1599.         if (!_owner.isTransparent()) {
  1600.             g.setColor(_owner._backgroundColor);
  1601.             if (nonSelectionRect != null) {
  1602.                 g.fillRect(nonSelectionRect);
  1603.                 TextView.returnRect(nonSelectionRect);
  1604.             }
  1605.             if (nonSelectionRect2 != null) {
  1606.                 g.fillRect(nonSelectionRect2);
  1607.                 TextView.returnRect(nonSelectionRect2);
  1608.             }
  1609.         }
  1610.  
  1611.         if (_owner.hasSelectionRange() && selectionRect != null && _owner.isSelectable()) {
  1612.  
  1613.             if (selectionRect.width == 0 && selectionRect.x == currentX) {
  1614.                 selectionRect.sizeTo(4, selectionRect.height);
  1615.             }
  1616.  
  1617.             if(!_owner.isEditing()) {
  1618.                 if(!_owner.isTransparent()) {
  1619.                     g.setColor(_owner._backgroundColor);
  1620.                     g.fillRect(selectionRect);
  1621.                 }
  1622.             } else {
  1623.                 g.setColor(_owner._selectionColor);
  1624.                 g.fillRect(selectionRect);
  1625.             }
  1626.  
  1627.             TextView.returnRect(selectionRect);
  1628.         }
  1629.     }
  1630.  
  1631.     void drawLine(Graphics g, int lineNumber) {
  1632.         TextStyleRun    nextRun;
  1633.         int             i, charCount = 0, runNumber = 1, currentX,
  1634.                         currentY, runChars, runStartChar, deltaX = 0,
  1635.                         maxWidth, availableWidth;
  1636.         TextParagraphFormat format = currentParagraphFormat();
  1637.  
  1638.         if (lineNumber >= _breakCount) {
  1639.             return;
  1640.         }
  1641.  
  1642.         maxWidth = _owner.bounds.width - format._leftMargin -
  1643.                    format._rightMargin;
  1644.         currentY = _y;
  1645.  
  1646.         if (!_owner.isTransparent()) {
  1647.             g.setColor(_owner._backgroundColor);
  1648.             g.fillRect(0, currentY, format._leftMargin,
  1649.                        _height);
  1650.             g.fillRect(_owner.bounds.width - format._rightMargin,
  1651.                        currentY, format._rightMargin + 1, _height);
  1652.         }
  1653.  
  1654.         nextRun = (TextStyleRun)_runVector.firstElement();
  1655.         runStartChar = 0;
  1656.         for (i = 0; i <= lineNumber; i++) {
  1657.             if (format._justification == Graphics.LEFT_JUSTIFIED) {
  1658.                 currentX = format._leftMargin;
  1659.             } else if (format._justification ==
  1660.                                     Graphics.RIGHT_JUSTIFIED) {
  1661.                 currentX = format._leftMargin +
  1662.                            _lineRemainders[i];
  1663.             } else {
  1664.                 currentX = format._leftMargin +
  1665.                            _lineRemainders[i] / 2;
  1666.             }
  1667.             availableWidth = maxWidth;
  1668.             if (i == 0) {
  1669.                 currentX += format._leftIndent;
  1670.                 availableWidth -= format._leftIndent;
  1671.             } else if( format.wrapsUnderFirstCharacter()) {
  1672.                 int newCurrentX = addWidthOfInitialTabs( currentX + format._leftIndent);
  1673.                 availableWidth -= (newCurrentX - currentX);
  1674.                 currentX = newCurrentX;
  1675.             }
  1676.  
  1677.             if (i == 0) {
  1678.                 charCount = _lineBreaks[i];
  1679.             } else {
  1680.                 charCount = _lineBreaks[i] - _lineBreaks[i - 1];
  1681.             }
  1682.  
  1683.             if (i == lineNumber) {
  1684.                 drawBackgroundForLine(g, i, currentX, currentY);
  1685.             }
  1686.  
  1687.             while (charCount > 0) {
  1688.                 runChars = nextRun.charCount() - runStartChar;
  1689.                 if (charCount >= runChars) {
  1690.                     if (i == lineNumber) {
  1691.                         deltaX = nextRun.drawCharacters(g, runStartChar,
  1692.                                                         runChars, currentX,
  1693.                                                         currentY +
  1694.                                                                 _baselines[i],
  1695.                                                        format._tabStops);
  1696.                     }
  1697.                     charCount -= runChars;
  1698.                     nextRun = (TextStyleRun)objectAt(_runVector, runNumber++);
  1699.                     while (nextRun != null && nextRun.charCount() == 0) {
  1700.                         nextRun = (TextStyleRun)objectAt(_runVector,
  1701.                                                                 runNumber++);
  1702.                     }
  1703.                     runStartChar = 0;
  1704.                 } else {
  1705.                     if (i == lineNumber) {
  1706.                         deltaX = nextRun.drawCharacters(g, runStartChar,
  1707.                                                         charCount, currentX,
  1708.                                                         currentY +
  1709.                                                                 _baselines[i],
  1710.                                                         format._tabStops);
  1711.                     }
  1712.                     runStartChar += charCount;
  1713.                     charCount = 0;
  1714.                 }
  1715.                 currentX += deltaX;
  1716.                 availableWidth -= deltaX;
  1717.             }
  1718.  
  1719.             currentY += _lineHeights[i];
  1720.         }
  1721.     }
  1722.  
  1723.     void drawView(Graphics g, Rect textBounds) {
  1724.         TextStyleRun    nextRun;
  1725.         Rect            lineRect, clipRect;
  1726.         int             i, charCount = 0, runNumber = 1, currentX, currentY,
  1727.                         runChars, runStartChar, deltaX, availableWidth,
  1728.                         maxWidth,defaultMaxWith;
  1729.         boolean         canDraw;
  1730.         TextParagraphFormat format = currentParagraphFormat();
  1731.         TextParagraphFormat defaultFormat = (TextParagraphFormat)
  1732.             _owner.defaultAttributes().get(TextView.PARAGRAPH_FORMAT_KEY);
  1733.  
  1734.         maxWidth = _owner.bounds.width - format._leftMargin -
  1735.                    format._rightMargin;
  1736.  
  1737.  
  1738.         currentY = _y;
  1739.  
  1740.         if (!_owner.isTransparent()) {
  1741.             g.setColor(_owner._backgroundColor);
  1742.             g.fillRect(textBounds.maxX() - defaultFormat._rightMargin,
  1743.                        currentY, defaultFormat._rightMargin + 1, _height);
  1744.         }
  1745.  
  1746.         nextRun = (TextStyleRun)_runVector.firstElement();
  1747.         runStartChar = 0;
  1748.         lineRect = TextView.newRect();
  1749.         clipRect = g.clipRect();
  1750.         for (i = 0; i < _breakCount; i++) {
  1751.             if (format._justification == Graphics.LEFT_JUSTIFIED) {
  1752.                 currentX = textBounds.x + format._leftMargin;
  1753.             } else if (format._justification ==
  1754.                                         Graphics.RIGHT_JUSTIFIED) {
  1755.                 currentX = textBounds.x + format._leftMargin +
  1756.                            _lineRemainders[i];
  1757.             } else {
  1758.                 currentX = textBounds.x + format._leftMargin +
  1759.                            _lineRemainders[i] / 2;
  1760.             }
  1761.             availableWidth = maxWidth;
  1762.             if (i == 0) {
  1763.                 currentX += format._leftIndent;
  1764.                 availableWidth -= format._leftIndent;
  1765.             } else if( format.wrapsUnderFirstCharacter()) {
  1766.                 int newCurrentX = addWidthOfInitialTabs( currentX + format._leftIndent);
  1767.                 availableWidth -= (newCurrentX - currentX);
  1768.                 currentX = newCurrentX;
  1769.             }
  1770.  
  1771.             if (i == 0) {
  1772.                 charCount = _lineBreaks[i];
  1773.             } else {
  1774.                 charCount = _lineBreaks[i] - _lineBreaks[i - 1];
  1775.             }
  1776.  
  1777.  
  1778.             lineRect.setBounds(0, currentY, _owner.bounds.width,
  1779.                                _lineHeights[i]);
  1780.             canDraw = clipRect.intersects(lineRect);
  1781.  
  1782.             if(!_owner.isTransparent()) {
  1783.                 g.setColor(_owner.backgroundColor());
  1784.                 g.fillRect(textBounds.x,currentY,currentX-textBounds.x,_lineHeights[i]);
  1785.             }
  1786.             if (canDraw) {
  1787.                 drawBackgroundForLine(g, i, currentX, currentY);
  1788.             }
  1789.             while (charCount > 0) {
  1790.                 runChars = nextRun.charCount() - runStartChar;
  1791.                 if (charCount >= runChars) {
  1792.                     if (canDraw) {
  1793.                         deltaX = nextRun.drawCharacters(g, runStartChar,
  1794.                                                         runChars, currentX,
  1795.                                                         currentY +
  1796.                                                                 _baselines[i],
  1797.                                                         format._tabStops);
  1798.                     } else {
  1799.                         deltaX = 0;
  1800.                     }
  1801.                     charCount -= runChars;
  1802.                     nextRun = (TextStyleRun)objectAt(_runVector, runNumber++);
  1803.                     while (nextRun != null && nextRun.charCount() == 0) {
  1804.                         nextRun = (TextStyleRun)objectAt(_runVector,
  1805.                                                                 runNumber++);
  1806.                     }
  1807.                     runStartChar = 0;
  1808.                 } else {
  1809.                     if (canDraw) {
  1810.                         deltaX = nextRun.drawCharacters(g, runStartChar,
  1811.                                                         charCount, currentX,
  1812.                                                         currentY +
  1813.                                                                 _baselines[i],
  1814.                                                         format._tabStops);
  1815.                     } else {
  1816.                         deltaX = 0;
  1817.                     }
  1818.                     runStartChar += charCount;
  1819.                     charCount = 0;
  1820.                 }
  1821.                 currentX += deltaX;
  1822.                 availableWidth -= deltaX;
  1823.             }
  1824.  
  1825.             currentY += _lineHeights[i];
  1826.         }
  1827.  
  1828.         TextView.returnRect(lineRect);
  1829.     }
  1830.  
  1831.     void draw() {
  1832.         Rect    tmpRect;
  1833.  
  1834.         if (_owner != null) {
  1835.             tmpRect = TextView.newRect(0, _y,
  1836.                                        _owner.bounds.width, _height);
  1837.             _owner.draw(tmpRect);
  1838.             TextView.returnRect(tmpRect);
  1839.         }
  1840.     }
  1841.  
  1842.     void subsumeParagraph(TextParagraph aParagraph) {
  1843.         TextStyleRun    nextRun;
  1844.         int             count, i;
  1845.  
  1846.         if (aParagraph == null) {
  1847.             return;
  1848.         }
  1849.  
  1850.         count = aParagraph._runVector.count();
  1851.         for (i = 0; i < count; i++) {
  1852.             nextRun = (TextStyleRun)aParagraph._runVector.elementAt(i);
  1853.             if (nextRun.charCount() > 0 ||
  1854.                 (_runVector.isEmpty() && i + 1 == count)) {
  1855.                 addRun(nextRun);
  1856.             }
  1857.         }
  1858.     }
  1859.  
  1860.     public String toString() {
  1861.         TextStyleRun            nextRun;
  1862.         FastStringBuffer        buffer;
  1863.         int                     i, count;
  1864.  
  1865.         buffer = new FastStringBuffer();
  1866.         buffer.append("[");
  1867.         count = _runVector.count();
  1868.         for (i = 0; i < count; i++) {
  1869.             nextRun = (TextStyleRun)_runVector.elementAt(i);
  1870.             buffer.append(nextRun.toString());
  1871.         }
  1872.         buffer.append("]\n");
  1873.         return buffer.toString();
  1874. /**        return dumpMe(); **/
  1875.     }
  1876.  
  1877.  
  1878.  
  1879. /* archiving */
  1880.  
  1881.  
  1882.     /** Describes the TextParagraph class' information.
  1883.       * @see Codable#describeClassInfo
  1884.       */
  1885.     public void describeClassInfo(ClassInfo info) {
  1886.         info.addClass("netscape.application.TextParagraph", 1);
  1887.         info.addField(FORMAT_KEY, OBJECT_TYPE);
  1888.         info.addField(RUNVECTOR_KEY, OBJECT_TYPE);
  1889.     }
  1890.  
  1891.     /** Encodes the TextParagraph instance.
  1892.       * @see Codable#encode
  1893.       */
  1894.     public void encode(Encoder encoder) throws CodingException {
  1895.         encoder.encodeObject(FORMAT_KEY, _format);
  1896.         encoder.encodeObject(RUNVECTOR_KEY, _runVector);
  1897.     }
  1898.  
  1899.     /** Decodes a TextParagraph instance.
  1900.       * @see Codable#decode
  1901.       */
  1902.     public void decode(Decoder decoder) throws CodingException {
  1903.         TextStyleRun    nextRun;
  1904.         int             i;
  1905.  
  1906.         _format = (TextParagraphFormat)decoder.decodeObject(FORMAT_KEY);
  1907.         _runVector = (Vector)decoder.decodeObject(RUNVECTOR_KEY);
  1908.  
  1909.         i = _runVector.count();
  1910.         while (i-- > 0) {
  1911.             nextRun = (TextStyleRun)_runVector.elementAt(i);
  1912.             nextRun.setParagraph(this);
  1913.         }
  1914.     }
  1915.  
  1916.     /** Finishes the TextParagraph instance decoding.  This method does
  1917.       * nothing.
  1918.       * @see Codable#finishDecoding
  1919.       */
  1920.     public void finishDecoding() throws CodingException {
  1921.     }
  1922.  
  1923.     /* Return the contents of the paragraph */
  1924.      String stringForRange(Range absoluteRange) {
  1925.         TextStyleRun run;
  1926.         StringBuffer sb = new StringBuffer();
  1927.         int i,c;
  1928.         int runIndex = _startChar;
  1929.         Range intersection = TextView.allocateRange();
  1930.         String s;
  1931.  
  1932.         for( i = 0 , c = _runVector.count() ; i < c ; i++ ) {
  1933.             run = (TextStyleRun)_runVector.elementAt(i);
  1934.             intersection.index  = runIndex;
  1935.             intersection.length = run.charCount();
  1936.             intersection.intersectWith( absoluteRange );
  1937.             if( intersection.index != Range.nullRange().index ) {
  1938.                 s = run.text().substring(intersection.index - runIndex,
  1939.                                                intersection.index - runIndex + intersection.length);
  1940.  
  1941.                 sb.append(s);
  1942.             }
  1943.             runIndex += run.charCount();
  1944.         }
  1945.         /* Does the range includes \n */
  1946.         if((absoluteRange.index + absoluteRange.length - 1) == (_startChar + _charCount - 1))
  1947.             sb.append("\n");
  1948.         TextView.recycleRange( intersection );
  1949.         return sb.toString();
  1950.     }
  1951.  
  1952.      Range range() {
  1953.         return TextView.allocateRange( _startChar, _charCount );
  1954.     }
  1955.  
  1956.     int lineCount() {
  1957.         return _breakCount;
  1958.     }
  1959. }
  1960.  
  1961.